package com.djhu.freepartner.web.control.aspect;

import com.djhu.freepartner.core.Status;
import com.djhu.freepartner.core.exception.ServiceException;
import com.djhu.freepartner.web.entity.enums.Limit;
import com.djhu.freepartner.web.entity.enums.LimitType;
import com.djhu.freepartner.web.support.HttpKit;
import com.google.common.base.Joiner;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class LimitAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${spring.freepartner.limit:10}")
    private Integer max_limit;

    @Pointcut(value = "@annotation(com.djhu.freepartner.web.entity.enums.Limit)")
    private void limitPointCut(){

    }

    @Around(value = "limitPointCut()")
    public Object doLimit(ProceedingJoinPoint point) throws Throwable {
        MethodSignature ms = (MethodSignature) point.getSignature();
        Method method = ms.getMethod();
        Limit limit = method.getAnnotation(Limit.class);
        if (limit.limit() < 0){
            try {
                return point.proceed();
            } catch (Throwable throwable) {
                throw throwable;
            }
        }
        String paramterkey= null;
        if (limit.limittype().equals(LimitType.IP)) {
            paramterkey = HttpKit.getIp();
        }else if (limit.limittype().equals(LimitType.USER)) {
            paramterkey = HttpKit.getRequestParameters().getOrDefault("userid","");
        }else {
            paramterkey = HttpKit.getRequestParameters().getOrDefault(limit.limitkey(),"");
        }
        String key = Joiner.on("_").useForNull("null").join(paramterkey,limit.name());
        if (redisTemplate.hasKey(key)){
            Integer count = Integer.valueOf(String.valueOf(redisTemplate.opsForValue().get(key)));
            if (count>max_limit){
                throw new ServiceException(Status.INVOKE_FREQUENTLY);
            }
            //计算 调用加1
            redisTemplate.opsForValue().increment(key,1);

        }else {
//            JSONObject jsonObject = new JSONObject();
//            jsonObject.put("timestamp",System.currentTimeMillis());
//            jsonObject.put("count",1);
            redisTemplate.opsForValue().set(key,String.valueOf(1),limit.time(),limit.timeUnit());
        }

        try {
            return point.proceed();
        } catch (Throwable throwable) {
            throw throwable;
        }
    }

}
